﻿using System;
using System.Diagnostics.Contracts;

namespace O1.Data.Traversal.Expressions
{
    [ContractVerification(true)]
    internal class DateTimePropertyExpression : PortableExpression
    {
        private static readonly Func<DateTimeProperty, DateTimeProperty, ObservationInterests>[] MethodTable =
           new Func<DateTimeProperty, DateTimeProperty, ObservationInterests>[PortableOperators.Comparisons.Count]
            {
                (queryValue, v) => (v.Key == queryValue.Key && (queryValue.Value == v.Value)) ? ObservationInterests.Interested : ObservationInterests.None,
                (queryValue, v) => (v.Key == queryValue.Key && (queryValue.Value != v.Value)) ? ObservationInterests.Interested : ObservationInterests.None,
                (queryValue, v) => (v.Key == queryValue.Key && (queryValue.Value < v.Value)) ? ObservationInterests.Interested : ObservationInterests.None,
                (queryValue, v) => (v.Key == queryValue.Key && (queryValue.Value > v.Value)) ? ObservationInterests.Interested : ObservationInterests.None,
                (queryValue, v) => (v.Key == queryValue.Key && (queryValue.Value <= v.Value)) ? ObservationInterests.Interested : ObservationInterests.None,
                (queryValue, v) => (v.Key == queryValue.Key && (queryValue.Value >= v.Value)) ? ObservationInterests.Interested : ObservationInterests.None,
            };

        private readonly DateTimeProperty property;

        public DateTimePropertyExpression(DateTimeProperty value, byte portableOperand)
            : base(portableOperand)
        {
            Contract.Requires(PortableOperators.Comparisons.Count > portableOperand);
            Contract.Assume(PortableOperators.Comparisons.Count == MethodTable.Length);
            this.property = value;
        }

        public override ObservationInterests Evaluate(DateTimeProperty value)
        {
            Contract.Assume(MethodTable[this.Operand] != null);
            return MethodTable[this.Operand](this.property, value);
        }

        [ContractInvariantMethod]
        private void ObjectInvariant()
        {
            Contract.Invariant(PortableOperators.Comparisons.Count > this.Operand);
            Contract.Invariant(PortableOperators.Comparisons.Count == MethodTable.Length);
            Contract.Invariant(this.Operand < MethodTable.Length);
        }
    }
}
